#include <GL/glew.h>
#include "scalebar.h"
#include "global.h"
#include "staticfunctions.h"

ScaleBars::ScaleBars()
{
  m_scalebars.clear();
}

ScaleBars::~ScaleBars() { clear(); }

bool ScaleBars::isValid() { return (m_scalebars.count() > 0); }

void
ScaleBars::clear()
{
  for(int i=0; i<m_scalebars.count(); i++)
    m_scalebars[i]->removeFromMouseGrabberPool();

  for(int i=0; i<m_scalebars.count(); i++)
    delete m_scalebars[i];

  m_scalebars.clear();
}

QList<ScaleBarObject>
ScaleBars::scalebars()
{
  QList<ScaleBarObject> scalist;
  for(int i=0; i<m_scalebars.count(); i++)
    scalist.append(m_scalebars[i]->scalebar());

  return scalist;
}


bool
ScaleBars::grabsMouse()
{
  for(int i=0; i<m_scalebars.count(); i++)
    {
      if (m_scalebars[i]->grabsMouse())
	return true;
    }
  return false;
}

void
ScaleBars::add(ScaleBarObject cap)
{
  ScaleBarGrabber *cmg = new ScaleBarGrabber();
  cmg->setScaleBar(cap);
  m_scalebars.append(cmg);
}

void
ScaleBars::setScaleBars(QList<ScaleBarObject> caps)
{
  clear();

  for(int i=0; i<caps.count(); i++)
    add(caps[i]);
}

#define VECPRODUCT(a, b) Vec(a.x*b.x, a.y*b.y, a.z*b.z)
void
ScaleBars::draw(QGLViewer *viewer)
{
  glDepthMask(GL_FALSE); // disable writing to depth buffer
  glDisable(GL_DEPTH_TEST);

  int screenWidth = viewer->size().width();
  int screenHeight = viewer->size().height();
  
  Vec vsc = viewer->camera()->sceneCenter();
  Vec vr = viewer->camera()->rightVector();    

  int cwd = viewer->camera()->screenWidth();
  int cht = viewer->camera()->screenHeight();
  float ratio = (float)cwd/(float)cht;

  VolumeInformation pvlInfo = Global::volumeInformation();

  QFont tfont = QFont("Helvetica", 12);
  tfont.setStyleStrategy(QFont::PreferAntialias);
  QFontMetrics metric(tfont);
  int mde = metric.descent();
  int fht = metric.height()+2;

  viewer->startScreenCoordinatesSystem();

  for(int i=0; i<m_scalebars.count(); i++)
    {
      QString str;
      ScaleBarGrabber *cmg = m_scalebars[i];
      bool horizontal = cmg->type();
      bool textpos = cmg->textpos();
      float slen = cmg->voxels();
      if (pvlInfo.voxelUnit > 0)
	{
	  float avg = (pvlInfo.voxelSize[0] +
		       pvlInfo.voxelSize[1] +
		       pvlInfo.voxelSize[2])/3.0f;

	  str = QString("%1 %2").\
	                arg(slen, 0, 'f', Global::floatPrecision()).\
	                arg(pvlInfo.voxelUnitStringShort());     

	  slen /= avg;
	}
      else
	str = QString("%1 voxels").arg(slen);


      Vec sp0 = viewer->camera()->projectedCoordinatesOf(vsc);
      Vec sp1 = viewer->camera()->projectedCoordinatesOf(vsc + slen*vr);

      slen = sp1.x - sp0.x;
      float slenw = slen;

      if (horizontal)
	slen *= (float)screenWidth/(float)cwd;
      else
	slen *= (float)screenHeight/(float)cht;

      QPointF pos = cmg->position();      
      Vec s0 = Vec(pos.x()*screenWidth,
		   pos.y()*screenHeight,
		   1);

      Vec s1 = s0;
      if (horizontal)
	{
	  s0 -= Vec(slen/2, 0, 0);
	  s1 += Vec(slen/2, 0, 0);
	}
      else
	{
	  s0 -= Vec(0, slen/2, 0);
	  s1 += Vec(0, slen/2, 0);
	}

      glEnable(GL_BLEND);
      glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA); // back to front
      glColor4f(0, 0, 0, 0.8f);
      if (cmg->grabsMouse())
	{
	  glColor4f(0.5f, 0, 0, 0.8f);
	  glBegin(GL_QUADS);
	  if (horizontal)
	    {
	      glVertex3f(s0.x-5, s0.y-10, 1);
	      glVertex3f(s1.x+5, s0.y-10, 1);
	      glVertex3f(s1.x+5, s0.y+10, 1);
	      glVertex3f(s0.x-5, s0.y+10, 1);
	    }
	  else
	    {
	      glVertex3f(s0.x-10, s0.y-5, 1);
	      glVertex3f(s0.x-10, s1.y+5, 1);
	      glVertex3f(s0.x+10, s1.y+5, 1);
	      glVertex3f(s0.x+10, s0.y-5, 1);
	    }
	  glEnd();
	}


      glDisable(GL_BLEND);
      glColor3f(1,1,1);
      glLineWidth(10);
      glBegin(GL_LINES);
      glVertex3fv(s0);
      glVertex3fv(s1);
      glEnd();
      glColor3f(0.5,0.5,0.5);
      glLineWidth(6);
      glBegin(GL_LINES);
      if (horizontal)
	{
	  glVertex3f(s0.x+1, s0.y, s0.z);
	  glVertex3f(s0.x+slen/2, s1.y, s1.z);
	}
      else
	{
	  glVertex3f(s1.x, s1.y-1, s0.z);
	  glVertex3f(s0.x, (s1.y+s0.y)/2, s1.z);
	}
      glEnd();
      glColor3f(0,0,0);
      glLineWidth(2);
      glBegin(GL_LINES);
      if (horizontal)
	{
	  glVertex3f(s0.x+1, s0.y, s0.z);
	  glVertex3f(s1.x-1, s1.y, s1.z);
	}
      else
	{
	  glVertex3f(s0.x, s0.y+1, s0.z);
	  glVertex3f(s1.x, s1.y-1, s1.z);
	}
      glEnd();
      glLineWidth(1);
      glColor3f(1,1,1);

      {
	Vec w0 = Vec(pos.x()*cwd, (1-pos.y())*cht,1);
	Vec w1 = w0;
	if (horizontal)
	  {
	    w0 -= Vec(slenw/2, 0, 0);
	    w1 += Vec(slenw/2, 0, 0);
	  }
	else
	  {
	    w0 -= Vec(0, slenw/2, 0);
	    w1 += Vec(0, slenw/2, 0);
	  }

	int fwd = metric.width(str)+2;
	QImage bImage = QImage(fwd, fht, QImage::Format_ARGB32);
	bImage.fill(0);
	QPainter bpainter(&bImage);
	Vec bgcolor = Global::backgroundColor();
	bpainter.setBackgroundMode(Qt::OpaqueMode);
	bpainter.setBackground(QColor(bgcolor.z*255,
				      bgcolor.y*255,
				      bgcolor.x*255));
	float bgintensity = (0.3*bgcolor.x +
			     0.5*bgcolor.y +
			     0.2*bgcolor.z);
	QColor penColor(Qt::white);
	if (bgintensity > 0.5) penColor = Qt::black;
	bpainter.setPen(penColor);
	bpainter.setFont(tfont);
	bpainter.drawText(1, fht-mde, str);

	QImage cImage = bImage.mirrored();
	if (!horizontal)
	  {	    
	    QMatrix matrix;
	    matrix.rotate(90);
	    cImage = cImage.transformed(matrix);
	  }
	int x,y;
	if (horizontal)
	  {
	    x = (w0.x+w1.x)/2 - cImage.width()/2;
	    y = w0.y-3-cImage.height();
	    if (!textpos)
	      y = w0.y+6;
	  }
	else
	  {
	    x = w1.x+3;
	    if (!textpos)
	      x = w1.x-5-cImage.width();
	    y = (w0.y+w1.y)/2 - cImage.height()/2;
	  }
	glWindowPos2i(x,y);
	const uchar *bits = cImage.bits();
	glDrawPixels(cImage.width(), cImage.height(),
		     GL_RGBA,
		     GL_UNSIGNED_BYTE,
		     bits);
      }
    }

  viewer->stopScreenCoordinatesSystem();
  glMatrixMode(GL_MODELVIEW);
  glPopMatrix();  
  
  glEnable(GL_DEPTH_TEST);
  glDepthMask(GL_TRUE); // enable writing to depth buffer
  glEnable(GL_BLEND);
}

bool
ScaleBars::keyPressEvent(QKeyEvent *event)
{
  for(int i=0; i<m_scalebars.count(); i++)
    {
      if (m_scalebars[i]->grabsMouse())
	{
	  if (event->key() == Qt::Key_Delete)
	    {
	      m_scalebars[i]->removeFromMouseGrabberPool();
	      m_scalebars.removeAt(i);
	    }
	  else if (event->key() == Qt::Key_H)
	    m_scalebars[i]->setType(true);
	  else if (event->key() == Qt::Key_V)
	    m_scalebars[i]->setType(false);
	  else if (event->key() == Qt::Key_D ||
		   event->key() == Qt::Key_R)
	    m_scalebars[i]->setTextpos(true);
	  else if (event->key() == Qt::Key_U ||
		   event->key() == Qt::Key_L)
	    m_scalebars[i]->setTextpos(false);
	}
    }
  
  return true;
}
